Skip to content

feat: expose JobFailedException and JobCancelledException at TSC top level - #1870

Open
jacalata wants to merge 2 commits into
developmentfrom
jac/expose-job-exceptions
Open

feat: expose JobFailedException and JobCancelledException at TSC top level#1870
jacalata wants to merge 2 commits into
developmentfrom
jac/expose-job-exceptions

Conversation

@jacalata

@jacalata jacalata commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Motivation

Neither the Job* exceptions raised by server.jobs.wait_for_job() nor the FlowRun* exceptions raised by server.flow_runs.wait_for_flow_run() are reachable from the top-level TSC namespace today — callers have to import from tableauserverclient.server.endpoint.exceptions, an internal module path. Reaching into a server.endpoint sub-package to catch a public failure signal is a bad pattern to teach.

Behavior change

  • Top-level TSC.JobFailedException, TSC.JobCancelledException, TSC.FlowRunFailedException, and TSC.FlowRunCancelledException are now importable, alongside FailedSignInError, MissingRequiredFieldError, NotSignedInError, and ServerResponseError.
  • Existing internal imports (tests, endpoints) are unchanged; purely additive.
  • Subclass relationships preserved: JobCancelledException remains a subclass of JobFailedException, and FlowRunCancelledException a subclass of FlowRunFailedException. Broad except JobFailedException and except FlowRunFailedException continue to catch both variants; code that wants to differentiate should catch the Cancelled variant first.
  • New test/test_import_surface.py guards all four names against silent regression of __init__.py.

Test plan

  • python -c "import tableauserverclient as TSC; assert issubclass(TSC.JobCancelledException, TSC.JobFailedException); assert issubclass(TSC.FlowRunCancelledException, TSC.FlowRunFailedException)" — passes.
  • All four names in TSC.__all__.
  • pytest test/test_import_surface.py — new tests pass.
  • CI green on the PR.

Followup

samples/list_jobs.py (added in #1843) currently reaches into the internal path. Once #1843 merges, a one-line followup PR will switch it to the top-level import.

🤖 Generated with Claude Code

…level

Both were previously reachable only via
`tableauserverclient.server.endpoint.exceptions`, which is an internal
module path. Callers waiting on a background job with
`server.jobs.wait_for_job()` need to catch these to distinguish a
failed job from a cancelled one (JobCancelledException is a subclass
of JobFailedException, so the order in an except-chain matters), and
reaching into a `server.endpoint` sub-package to do so is a bad
pattern to teach.

Re-export them alongside the other exception types already exposed at
the top level (FailedSignInError, MissingRequiredFieldError,
NotSignedInError, ServerResponseError). Existing internal imports in
tests and endpoints remain unchanged; this is purely additive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tableauserverclient
   __init__.py50100% 
   config.py150100% 
   datetime_helpers.py2511 96%
   exponential_backoff.py200100% 
   filesys_helpers.py310100% 
   namespace.py2533 88%
tableauserverclient/bin
   __init__.py20100% 
   _version.py358212212 41%
tableauserverclient/helpers
   __init__.py10100% 
   logging.py20100% 
   strings.py3111 97%
tableauserverclient/models
   __init__.py460100% 
   collection_item.py4177 83%
   column_item.py553232 42%
   connection_credentials.py351111 69%
   connection_item.py941414 85%
   custom_view_item.py1442121 85%
   data_acceleration_report_item.py5411 98%
   data_alert_item.py15844 97%
   data_freshness_policy_item.py1551515 90%
   database_item.py2073636 83%
   datasource_item.py3001212 96%
   dqw_item.py10455 95%
   exceptions.py40100% 
   extensions_item.py13244 97%
   extract_item.py4444 91%
   favorites_item.py6988 88%
   fileupload_item.py190100% 
   flow_item.py1491010 93%
   flow_run_item.py710100% 
   group_item.py8966 93%
   groupset_item.py4977 86%
   interval_item.py1823232 82%
   job_item.py1921010 95%
   linked_tasks_item.py7911 99%
   location_item.py2922 93%
   metric_item.py1291313 90%
   oidc_item.py6333 95%
   pagination_item.py3411 97%
   permissions_item.py1111212 89%
   project_item.py2073131 85%
   property_decorators.py1001818 82%
   reference_item.py2622 92%
   revision_item.py5911 98%
   schedule_item.py20966 97%
   server_info_item.py3777 81%
   site_item.py6361313 98%
   subscription_item.py10122 98%
   table_item.py1191818 85%
   tableau_auth.py612525 59%
   tableau_types.py2711 96%
   tag_item.py150100% 
   target.py60100% 
   task_item.py5622 96%
   user_item.py3381717 95%
   view_item.py2201616 93%
   virtual_connection_item.py6488 88%
   webhook_item.py6911 99%
   workbook_item.py3621616 96%
tableauserverclient/server
   __init__.py90100% 
   exceptions.py40100% 
   filter.py2911 97%
   pager.py3311 97%
   query.py1431515 90%
   request_factory.py1335195195 85%
   request_options.py38655 99%
   server.py2492525 90%
   sort.py60100% 
tableauserverclient/server/endpoint
   __init__.py350100% 
   auth_endpoint.py731010 86%
   custom_views_endpoint.py1521212 92%
   data_acceleration_report_endpoint.py210100% 
   data_alert_endpoint.py942323 76%
   databases_endpoint.py1113030 73%
   datasources_endpoint.py3233333 90%
   default_permissions_endpoint.py4433 93%
   dqw_endpoint.py451616 64%
   endpoint.py2612525 90%
   exceptions.py7966 92%
   extensions_endpoint.py310100% 
   favorites_endpoint.py942222 77%
   fileuploads_endpoint.py510100% 
   flow_runs_endpoint.py6299 85%
   flow_task_endpoint.py2122 90%
   flows_endpoint.py1985353 73%
   groups_endpoint.py12699 93%
   groupsets_endpoint.py7277 90%
   jobs_endpoint.py6799 87%
   linked_tasks_endpoint.py370100% 
   metadata_endpoint.py881414 84%
   metrics_endpoint.py5566 89%
   oidc_endpoint.py4211 98%
   permissions_endpoint.py4433 93%
   projects_endpoint.py1782424 87%
   resource_tagger.py1273535 72%
   schedules_endpoint.py1191111 91%
   server_info_endpoint.py361010 72%
   sites_endpoint.py1302727 79%
   subscriptions_endpoint.py561414 75%
   tables_endpoint.py1103636 67%
   tasks_endpoint.py6366 90%
   users_endpoint.py17077 96%
   views_endpoint.py15099 94%
   virtual_connections_endpoint.py1131010 91%
   webhooks_endpoint.py5499 83%
   workbooks_endpoint.py3382222 93%
TOTAL12129142788% 

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is purely additive and consistently updates both the import surface and __all__ exports needed for the new public API.

Pull request overview

Exposes JobFailedException and JobCancelledException as part of the public TSC top-level API so callers using server.jobs.wait_for_job() can catch these exceptions without importing from an internal server.endpoint path.

Changes:

  • Re-export JobFailedException / JobCancelledException from tableauserverclient.server (and include them in server.__all__).
  • Re-export the same exceptions from the package top level tableauserverclient (and include them in TSC.__all__).
File summaries
File Description
tableauserverclient/server/init.py Adds JobFailedException / JobCancelledException to server-level imports and __all__ for public export.
tableauserverclient/init.py Adds JobFailedException / JobCancelledException to top-level imports and __all__ so they’re available as TSC.*.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…op level

Same shape and same private-path problem as the Job exceptions this PR is
already fixing. flow_runs.wait_for_flow_run() raises these; users need to
catch them without importing from server.endpoint.exceptions.

Add regression tests for both pairs so a future refactor of __init__.py
can't silently break the public surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants